/*     */ package com.zimbra.cs.filter;
/*     */ 
/*     */ import com.zimbra.client.ZFolder;
/*     */ import com.zimbra.client.ZFolder.View;
/*     */ import com.zimbra.client.ZMailbox;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.soap.Element;
/*     */ import com.zimbra.common.soap.Element.ElementFactory;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.Pair;
/*     */ import com.zimbra.common.util.StringUtil;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.mailbox.Folder;
/*     */ import com.zimbra.cs.mailbox.Folder.FolderOptions;
/*     */ import com.zimbra.cs.mailbox.MailItem.Type;
/*     */ import com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.mailbox.Mountpoint;
/*     */ import com.zimbra.cs.service.util.ItemId;
/*     */ import java.util.ArrayList;
/*     */ import java.util.HashSet;
/*     */ import java.util.Iterator;
/*     */ import java.util.List;
/*     */ import java.util.Set;
/*     */ import java.util.Stack;
/*     */ import java.util.regex.Matcher;
/*     */ import java.util.regex.Pattern;
/*     */ import org.apache.jsieve.parser.SieveNode;
/*     */ import org.apache.jsieve.parser.generated.ASTargument;
/*     */ import org.apache.jsieve.parser.generated.ASTcommand;
/*     */ import org.apache.jsieve.parser.generated.ASTstring;
/*     */ import org.apache.jsieve.parser.generated.ASTstring_list;
/*     */ import org.apache.jsieve.parser.generated.ASTtest;
/*     */ import org.apache.jsieve.parser.generated.Node;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class RuleRewriter
/*     */ {
/*  60 */   static final Set<String> MATCH_TYPES = new HashSet();
/*     */   
/*  62 */   static { MATCH_TYPES.add(":is");
/*  63 */     MATCH_TYPES.add(":contains");
/*  64 */     MATCH_TYPES.add(":matches");
/*  65 */     MATCH_TYPES.add(":over");
/*  66 */     MATCH_TYPES.add(":under");
/*  67 */     MATCH_TYPES.add(":in");
/*  68 */     MATCH_TYPES.add(":before");
/*  69 */     MATCH_TYPES.add(":after"); }
/*     */   
/*  71 */   private final Stack<String> mStack = new Stack();
/*     */   
/*     */ 
/*     */   private Element mRoot;
/*     */   
/*     */ 
/*     */   private List<String> mRuleNames;
/*     */   
/*     */   private Mailbox mMailbox;
/*     */   
/*     */   private static final int K = 1024;
/*     */   
/*     */   private static final int M = 1048576;
/*     */   
/*     */ 
/*     */   void initialize(Element.ElementFactory factory, Node node, List<String> ruleNames)
/*     */   {
/*  88 */     this.mRoot = factory.createElement("rules");
/*  89 */     this.mRuleNames = ruleNames;
/*  90 */     traverse(node);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   void initialize(Element eltRules, Mailbox mbox)
/*     */   {
/* 100 */     this.mRoot = eltRules;
/* 101 */     this.mMailbox = mbox;
/*     */   }
/*     */   
/*     */   Element getElement() {
/* 105 */     return this.mRoot;
/*     */   }
/*     */   
/*     */   private void traverse(Node node) {
/* 109 */     int numChildren = node.jjtGetNumChildren();
/* 110 */     int nameIndex = 0;
/* 111 */     for (int i = 0; i < numChildren; i++) {
/* 112 */       Node childNode = node.jjtGetChild(i);
/* 113 */       String name = ((SieveNode)childNode).getName();
/* 114 */       if (((childNode instanceof ASTcommand)) && (("if".equals(name)) || ("elsif".equals(name)) || ("disabled_if".equals(name))))
/*     */       {
/* 116 */         String ruleName = "";
/* 117 */         if ((this.mRuleNames != null) && (nameIndex < this.mRuleNames.size())) {
/* 118 */           ruleName = (String)this.mRuleNames.get(nameIndex);
/* 119 */           nameIndex++;
/*     */         }
/*     */         
/* 122 */         Element ruleElem = this.mRoot.addElement("r").addAttribute("name", ruleName);
/*     */         
/* 124 */         ruleElem.addAttribute("active", !"disabled_if".equals(name));
/* 125 */         rule(ruleElem, childNode);
/*     */       } else {
/* 127 */         traverse(childNode);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private void rule(Element elem, Node parent)
/*     */   {
/* 134 */     int numChildren = parent.jjtGetNumChildren();
/* 135 */     for (int i = 0; i < numChildren; i++) {
/* 136 */       Node node = parent.jjtGetChild(i);
/* 137 */       String name = ((SieveNode)node).getName();
/* 138 */       if ((node instanceof ASTtest)) {
/* 139 */         if (("anyof".equals(name)) || ("allof".equals(name))) {
/* 140 */           Element condsElem = elem.addElement("g").addAttribute("op", name);
/*     */           
/* 142 */           rule(condsElem, node);
/* 143 */         } else if ("not".equals(name)) {
/* 144 */           this.mStack.push(name);
/* 145 */           rule(elem, node);
/*     */         } else {
/* 147 */           if (("exists".equals(name)) && (!this.mStack.isEmpty())) {
/* 148 */             name = (String)this.mStack.pop() + " " + name;
/*     */           }
/* 150 */           Element cElem = elem.addElement("c").addAttribute("name", name);
/*     */           
/* 152 */           this.x = 0;
/* 153 */           test(cElem, node);
/*     */         }
/* 155 */       } else if ((node instanceof ASTcommand)) {
/* 156 */         Element actionElem = elem.addElement("action").addAttribute("name", ((SieveNode)node).getName());
/*     */         
/* 158 */         action(actionElem, node);
/*     */       } else {
/* 160 */         rule(elem, node);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private void test(Element elem, Node node) {
/* 166 */     int numChildren = node.jjtGetNumChildren();
/* 167 */     for (int i = 0; i < numChildren; i++) {
/* 168 */       Node childNode = node.jjtGetChild(i);
/* 169 */       if ((childNode instanceof ASTargument)) {
/* 170 */         Object val = ((SieveNode)childNode).getValue();
/* 171 */         if (val != null) {
/* 172 */           if (MATCH_TYPES.contains(val.toString())) {
/* 173 */             if (!this.mStack.isEmpty())
/* 174 */               val = (String)this.mStack.pop() + " " + val;
/* 175 */             elem.addAttribute("op", val.toString());
/*     */           } else {
/* 177 */             String cname = elem.getAttribute("name", null);
/* 178 */             if ("size".equals(cname))
/*     */             {
/* 180 */               elem.addAttribute("k1", getSize(val.toString()));
/*     */             } else {
/* 182 */               elem.addAttribute("mod", val.toString());
/*     */             }
/*     */           }
/*     */         }
/* 186 */       } else if ((childNode instanceof ASTstring_list)) {
/* 187 */         List<Object> val = getStringList(childNode);
/* 188 */         String cname = elem.getAttribute("name", null);
/* 189 */         String param = null;
/* 190 */         if (("date".equals(cname)) || ("body".equals(cname))) {
/* 191 */           param = "k1";
/*     */         } else
/* 193 */           param = PARAM_PREFIX + String.valueOf(this.x++);
/* 194 */         elem.addAttribute(param, toString(val));
/*     */       }
/* 196 */       test(elem, childNode);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   private static String toString(List<Object> list)
/*     */   {
/* 205 */     StringBuilder buf = new StringBuilder();
/* 206 */     buf.append("[");
/* 207 */     boolean isFirst; if (list != null) {
/* 208 */       isFirst = true;
/*     */       
/* 210 */       for (Object val : list) {
/* 211 */         if (isFirst) {
/* 212 */           isFirst = false;
/*     */         } else {
/* 214 */           buf.append(", ");
/*     */         }
/* 216 */         String sVal = String.valueOf(val);
/* 217 */         if (val == null) {
/* 218 */           buf.append(sVal);
/*     */         } else {
/* 220 */           if (!sVal.startsWith("\"")) {
/* 221 */             buf.append('"');
/*     */           }
/* 223 */           buf.append(sVal);
/* 224 */           if (!sVal.endsWith("\"")) {
/* 225 */             buf.append('"');
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/* 230 */     buf.append("]");
/* 231 */     return buf.toString();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private String getSize(String szStr)
/*     */   {
/* 242 */     int sz = Integer.parseInt(szStr);
/* 243 */     if (sz % 1048576 == 0)
/* 244 */       return sz / 1048576 + "M";
/* 245 */     if (sz % 1024 == 0) {
/* 246 */       return sz / 1024 + "K";
/*     */     }
/* 248 */     return szStr + "B";
/*     */   }
/*     */   
/* 251 */   private static final char PARAM_PREFIX = "k0".charAt(0);
/*     */   
/* 253 */   private int x = 0;
/*     */   
/*     */   private List<Object> getStringList(Node node) {
/* 256 */     int n = node.jjtGetNumChildren();
/* 257 */     List<Object> a = new ArrayList(n);
/* 258 */     for (int i = 0; i < n; i++) {
/* 259 */       Node cn = node.jjtGetChild(i);
/* 260 */       a.add(((SieveNode)cn).getValue());
/*     */     }
/* 262 */     return a;
/*     */   }
/*     */   
/*     */   private void action(Element elem, Node node) {
/* 266 */     int numChildren = node.jjtGetNumChildren();
/* 267 */     for (int i = 0; i < numChildren; i++) {
/* 268 */       Node childNode = node.jjtGetChild(i);
/* 269 */       if ((childNode instanceof ASTstring)) {
/* 270 */         String val = ((SieveNode)childNode).getValue().toString();
/* 271 */         if (val.startsWith("text:")) {
/* 272 */           elem.addText(val.substring(5));
/*     */         }
/*     */         else
/*     */         {
/* 276 */           StringBuilder buf = new StringBuilder();
/* 277 */           if (!val.startsWith("\"")) {
/* 278 */             buf.append('"');
/*     */           }
/* 280 */           buf.append(val);
/* 281 */           if (!val.endsWith("\"")) {
/* 282 */             buf.append('"');
/*     */           }
/*     */           
/* 285 */           elem.addElement("arg").setText(buf.toString());
/*     */         }
/*     */       } else {
/* 288 */         action(elem, childNode);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static void sanitizeRules(Element element)
/*     */     throws ServiceException
/*     */   {
/* 305 */     if (element == null) {
/* 306 */       return;
/*     */     }
/* 308 */     for (Element child : element.listElements()) {
/* 309 */       sanitizeRules(child);
/*     */     }
/*     */     
/* 312 */     if (element.getName().equals("c")) {
/* 313 */       String k0 = element.getAttribute("k0", null);
/* 314 */       if (k0 != null) {
/* 315 */         element.addAttribute("k0", stripBracketsAndQuotes(k0));
/*     */       }
/* 317 */       String k1 = element.getAttribute("k1", null);
/* 318 */       if (k1 != null) {
/* 319 */         element.addAttribute("k1", stripBracketsAndQuotes(k1));
/*     */       }
/* 321 */     } else if (element.getName().equals("arg")) {
/* 322 */       element.setText(stripBracketsAndQuotes(element.getText()));
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public String getScript()
/*     */     throws ServiceException
/*     */   {
/* 331 */     StringBuffer sb = new StringBuffer();
/* 332 */     traverse(sb, this.mRoot);
/* 333 */     String script = sb.toString();
/* 334 */     if (script.trim().length() > 0)
/*     */     {
/* 336 */       script = "require [\"fileinto\", \"reject\", \"tag\", \"flag\"];\n\n" + script;
/*     */     }
/* 338 */     return script;
/*     */   }
/*     */   
/*     */ 
/*     */   private void traverse(StringBuffer sb, Element element)
/*     */     throws ServiceException
/*     */   {
/* 345 */     for (Iterator<Element> it = element.elementIterator(); it.hasNext();) {
/* 346 */       Element subnode = (Element)it.next();
/* 347 */       String nodeName = subnode.getName();
/* 348 */       if ("r".equals(nodeName)) {
/* 349 */         String ruleName = subnode.getAttribute("name");
/* 350 */         sb.append("# " + ruleName + "\n");
/* 351 */         boolean active = subnode.getAttributeBool("active", true);
/* 352 */         sb.append(active ? "if " : "disabled_if ");
/* 353 */         condition(sb, subnode, false, ruleName);
/*     */       } else {
/* 355 */         traverse(sb, subnode);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */   private void condition(StringBuffer sb, Element element, boolean group, String ruleName)
/*     */     throws ServiceException
/*     */   {
/* 364 */     boolean actionOpenBrace = false;
/* 365 */     boolean firstConditionInGroup = true;
/*     */     
/* 367 */     for (Iterator<Element> it = element.elementIterator(); it.hasNext();) {
/* 368 */       Element subnode = (Element)it.next();
/* 369 */       String nodeName = subnode.getName();
/* 370 */       if ("g".equals(nodeName)) {
/* 371 */         if (!firstConditionInGroup) {
/* 372 */           sb.append(", ");
/*     */         } else {
/* 374 */           firstConditionInGroup = false;
/*     */         }
/* 376 */         sb.append(subnode.getAttribute("op")).append(" (");
/* 377 */         condition(sb, subnode, true, ruleName);
/* 378 */         sb.append(")\n");
/* 379 */       } else if ("c".equals(nodeName)) {
/* 380 */         if (group) {
/* 381 */           if (!firstConditionInGroup) {
/* 382 */             sb.append(",\n ");
/*     */           } else
/* 384 */             firstConditionInGroup = false;
/*     */         }
/* 386 */         String testName = subnode.getAttribute("name");
/* 387 */         boolean isSize = "size".equals(testName);
/* 388 */         String op = subnode.getAttribute("op", null);
/* 389 */         if ((op != null) && (op.startsWith("not")))
/*     */         {
/*     */ 
/*     */ 
/* 393 */           testName = "not " + testName;
/* 394 */           op = op.substring(3).trim();
/*     */         }
/* 396 */         sb.append(testName).append(" ");
/* 397 */         if (op != null)
/* 398 */           sb.append(op).append(" ");
/* 399 */         String k0 = subnode.getAttribute("k0", null);
/* 400 */         checkValue(k0, ruleName);
/* 401 */         if (k0 != null)
/* 402 */           sb.append("\"").append(k0).append("\"").append(" ");
/* 403 */         String k1 = subnode.getAttribute("k1", null);
/* 404 */         checkValue(k1, ruleName);
/* 405 */         if (k1 != null) {
/* 406 */           if (!isSize)
/* 407 */             sb.append("\"");
/* 408 */           sb.append(k1);
/* 409 */           if (!isSize)
/* 410 */             sb.append("\"");
/*     */         }
/* 412 */         sb.append(" ");
/*     */         
/*     */ 
/* 415 */         if ((":matches".equals(op)) && (k1 != null) && (k1.contains("*****"))) {
/* 416 */           throw ServiceException.INVALID_REQUEST("Wildcard match value cannot contain more than four asterisks in a row.", null);
/*     */         }
/*     */       }
/* 419 */       else if ("action".equals(nodeName)) {
/* 420 */         if (!actionOpenBrace) {
/* 421 */           sb.append("{\n");
/* 422 */           actionOpenBrace = true;
/*     */         }
/* 424 */         String actionName = subnode.getAttribute("name");
/* 425 */         sb.append("    ").append(actionName);
/* 426 */         action(sb, actionName, subnode, ruleName);
/*     */       }
/*     */     }
/* 429 */     if (actionOpenBrace) {
/* 430 */       sb.append("}\n");
/*     */     }
/*     */   }
/*     */   
/* 434 */   private static final Pattern PAT_BRACKET_QUOTES = Pattern.compile("\\[\"(.*)\"\\]");
/*     */   
/* 436 */   private static final Pattern PAT_QUOTES = Pattern.compile("\"(.*)\"");
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static String stripBracketsAndQuotes(String s)
/*     */   {
/* 450 */     if (s != null)
/*     */     {
/* 452 */       Matcher matcher = PAT_BRACKET_QUOTES.matcher(s);
/* 453 */       if (matcher.matches()) {
/* 454 */         s = matcher.group(1);
/*     */       } else {
/* 456 */         matcher = PAT_QUOTES.matcher(s);
/* 457 */         if (matcher.matches()) {
/* 458 */           s = matcher.group(1);
/*     */         }
/*     */       }
/*     */     }
/* 462 */     return s;
/*     */   }
/*     */   
/*     */   private void checkValue(String k, String ruleName) throws ServiceException
/*     */   {
/* 467 */     if (k == null) {
/* 468 */       return;
/*     */     }
/* 470 */     if (k.contains("\"")) {
/* 471 */       String msg = String.format("Doublequote not allowed for value '%s' in filter rule %s", new Object[] { k, ruleName });
/*     */       
/* 473 */       throw ServiceException.INVALID_REQUEST(msg, null);
/*     */     }
/* 475 */     if (k.contains("\\")) {
/* 476 */       String msg = String.format("Backslash not allowed for value '%s' in filter rule %s", new Object[] { k, ruleName });
/*     */       
/* 478 */       throw ServiceException.INVALID_REQUEST(msg, null);
/*     */     }
/*     */   }
/*     */   
/*     */   void action(StringBuffer sb, String actionName, Element element, String ruleName) throws ServiceException {
/* 483 */     for (Iterator<Element> it = element.elementIterator("arg"); it.hasNext();) {
/* 484 */       Element subnode = (Element)it.next();
/* 485 */       String argVal = subnode.getText();
/* 486 */       if ("fileinto".equals(actionName)) {
/* 487 */         createFolderIfNecessary(argVal, ruleName);
/* 488 */       } else if ("tag".equals(actionName)) {
/*     */         try
/*     */         {
/* 491 */           this.mMailbox.getTagByName(null, argVal);
/*     */         }
/*     */         catch (MailServiceException.NoSuchItemException e) {
/* 494 */           this.mMailbox.createTag(null, argVal, (byte)0);
/* 495 */           ZimbraLog.filter.info("Created tag " + argVal + " referenced in rule \"" + ruleName + "\"");
/*     */         }
/*     */       }
/* 498 */       sb.append(" \"").append(argVal).append("\"");
/*     */     }
/* 500 */     sb.append(";\n");
/*     */   }
/*     */   
/*     */   private void createFolderIfNecessary(String path, String ruleName) throws ServiceException
/*     */   {
/* 505 */     Pair<Folder, String> folderAndRemotePath = this.mMailbox.getFolderByPathLongestMatch(null, 1, path);
/*     */     
/* 507 */     Folder folder = (Folder)folderAndRemotePath.getFirst();
/* 508 */     String remotePath = (String)folderAndRemotePath.getSecond();
/* 509 */     if (StringUtil.isNullOrEmpty(remotePath)) {
/* 510 */       remotePath = null;
/*     */     }
/*     */     
/* 513 */     if (((folder instanceof Mountpoint)) && (remotePath != null))
/*     */     {
/* 515 */       Mountpoint mountpoint = (Mountpoint)folder;
/* 516 */       ZimbraLog.filter.info("Creating folder %s in remote folder %s for rule %s.", new Object[] { remotePath, folder.getPath(), ruleName });
/*     */       
/* 518 */       ZMailbox remoteMbox = FilterUtil.getRemoteZMailbox(this.mMailbox, (Mountpoint)folder);
/* 519 */       ItemId id = mountpoint.getTarget();
/* 520 */       ZFolder parent = remoteMbox.getFolderById(id.toString());
/* 521 */       if (parent == null) {
/* 522 */         String msg = String.format("Could not find folder with id %d in remote mailbox %s.", new Object[] { Integer.valueOf(mountpoint.getRemoteId()), mountpoint.getOwnerId() });
/*     */         
/* 524 */         throw ServiceException.FAILURE(msg, null);
/*     */       }
/* 526 */       String[] pathElements = remotePath.split("/");
/* 527 */       for (String folderName : pathElements) {
/* 528 */         if (!StringUtil.isNullOrEmpty(folderName)) {
/* 529 */           ZFolder currentFolder = parent.getSubFolderByPath(folderName);
/* 530 */           if (currentFolder != null) {
/* 531 */             parent = currentFolder;
/*     */           } else {
/* 533 */             parent = remoteMbox.createFolder(parent.getId(), folderName, ZFolder.View.message, null, null, null);
/*     */           }
/*     */         }
/*     */       }
/* 537 */     } else if (remotePath != null)
/*     */     {
/* 539 */       ZimbraLog.filter.info("Creating folder %s for rule %s.", new Object[] { path, ruleName });
/* 540 */       this.mMailbox.createFolder(null, path, new Folder.FolderOptions().setDefaultView(MailItem.Type.MESSAGE));
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/filter/RuleRewriter.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */